/* bmpscxr.p - PRODUCT STRUCTURE COMPONENT RESPONSIBILITY-OWNING PROGRAM      */
/* Copyright 1986-2003 QAD Inc., Carpinteria, CA, USA.                        */
/* All rights reserved worldwide.  This is an unpublished work.               */
/* $Revision: 1.10 $                                                           */
/*                                                                            */
/* This routine provides the procedures which are executed as a result of     */
/* calls from the appropriate Data Type Controllers / structured programs.    */
/* It contains business logic pertaining to Product Structure Maintenance.    */
/*                                                                            */
/*  Revision: 1.2        BY: Evan Bishop      DATE: 06/01/00     ECO: *N0B9*  */
/*  Revision: 1.3        BY: Paul Donnelly    DATE: 07/16/00     ECO: *N0DP*  */
/*  Revision: 1.4        BY: Evan Bishop      DATE: 08/01/00     ECO: *N0GY*  */
/*  Revision: 1.6        BY: Evan Bishop      DATE: 08/01/00     ECO: *N0JP*  */
/* REVISION: 9.1    LAST MODIFIED: 08/11/00 BY: *N0KK* jyn                    */
/* Revision: 1.7         BY: Hualin Zhong     DATE: 08/15/00     ECO: *N0L2*  */
/* Revision: 1.8         BY: Murali Ayyagari  DATE: 12/14/00     ECO: *N0V1*  */
/* Revision: 1.9         BY: Mark Christian   DATE: 05/05/01     ECO: *N0YF*  */
/* $Revision: 1.10 $      BY: Vandna Rohira    DATE: 04/16/03     ECO: *N2D7*  */

/******************************************************************************/
/* All patch markers and commented out code have been removed from the source */
/* code below. For all future modifications to this file, any code which is   */
/* no longer required should be deleted and no in-line patch markers should   */
/* be added.  The ECO marker should only be included in the Revision History. */
/******************************************************************************/
/*                                                                            */
/*V8:ConvertMode=NoConvert                                                    */

{mfdeclre.i}
{pxmaint.i}

/* Define Handles for the programs. */
{pxphdef.i gpcodxr}
/* End Define Handles for the programs. */

/* ========================================================================= */
/* ******************************** FUNCTIONS ****************************** */
/* ========================================================================= */

/* ========================================================================= */
/* ************************** INTERNAL PROCEDURES ************************** */
/* ========================================================================= */


/*===========================================================================*/
PROCEDURE processCreate:
/*---------------------------------------------------------------------------
      Purpose:  Creates a record in the product structure component buffer.
   Exceptions:  NONE
        Notes:
      History:
---------------------------------------------------------------------------*/
   define input parameter pParentItem as character no-undo.
   define input parameter pComponentItem as character no-undo.
   define input parameter pReferenceCode as character no-undo.
   define input parameter pStartEffective as date no-undo.
   define input parameter pQuantityType as character no-undo.
   define  parameter buffer pProductStructureBuffer for ps_mstr.

   define variable addPSValue as character initial "ADD-PS".

   do on error undo, return error {&GENERAL-APP-EXCEPT}:
       /* GHS
      {pxrun.i &PROC = 'validateItemStatus'
              &PARAM = "(input pParentItem, input addPSValue)"
      }
      if return-value <> {&SUCCESS-RESULT} then
         undo, return error return-value.
       */
      {pxrun.i &PROC = 'validateBomExists'
              &PARAM = "(input pParentItem)"
         &FIELD-LIST = "bom_parent"
      }
      if return-value <> {&SUCCESS-RESULT} then
         undo, return error return-value.

      FIND first pt_mstr no-lock where pt_part = pParentItem AND pt_status <> 'TA'   NO-ERROR.
      IF AVAIL(pt_mstr) THEN DO: /*ghs*/
            
          {pxrun.i &PROC = 'validateItemStatus'
                  &PARAM = "(input pComponentItem, input addPSValue)"
          }
          if return-value <> {&SUCCESS-RESULT} then
             undo, return error return-value.

      END.

      {pxrun.i &PROC = 'validateBomExists'
              &PARAM = "(input pComponentItem)"
         &FIELD-LIST = "ps_comp"
      }
      if return-value <> {&SUCCESS-RESULT} then
         undo, return error return-value.

      create pProductStructureBuffer.
      assign ps_par = pParentItem
            ps_comp = pComponentItem
             ps_ref = pReferenceCode
           ps_start = pStartEffective
        ps_qty_type = pQuantityType.

      if recid(pProductStructureBuffer) = -1 then.

      {pxrun.i &PROC = 'validateCyclicStructures'
              &PARAM = "(input recid(pProductStructureBuffer))"
      }
      if return-value <> {&SUCCESS-RESULT} then
         undo, return error return-value.

   end. /* do on error undo, return {&GENERAL-APP-EXCEPT}: */
   return {&SUCCESS-RESULT}.
END PROCEDURE. /* processCreate */

/*===========================================================================*/
PROCEDURE processDelete:
/*---------------------------------------------------------------------------
      Purpose:  Deletes Product Structure Component record.
   Exceptions:  NONE
        Notes:
      History:
---------------------------------------------------------------------------*/
   define parameter buffer pProductStructureBuffer for ps_mstr.

   define variable updateLevels as logical initial no no-undo.

   do on error undo, return error {&GENERAL-APP-EXCEPT}:

      {pxrun.i &PROC = 'updateMrpFlags'
              &PARAM = "(input pProductStructureBuffer.ps_par,updateLevels)"
      }

      /* Delete product structure component record */
      delete pProductStructureBuffer.

   end. /* do on error undo, return {&GENERAL-APP-EXCEPT}: */
   return {&SUCCESS-RESULT}.
END PROCEDURE. /* processDelete */

/*===========================================================================*/
PROCEDURE maintainBatchQtyPer:
/*---------------------------------------------------------------------------
      Purpose:  Set quantity per batch and percent of batch fields for
                product structure records
   Exceptions:  NONE
        Notes:
      History:
---------------------------------------------------------------------------*/
   define parameter buffer pProductStructureBuffer for ps_mstr.

   define buffer bom_mstrBuffer for bom_mstr.

   do on error undo, return error {&GENERAL-APP-EXCEPT}:

      if ps_qty_type = "" then do:
         assign ps_qty_per_b = ps_qty_per
                ps_batch_pct = 0.
      end.
   end. /* do on error undo, return {&GENERAL-APP-EXCEPT}: */

   return {&SUCCESS-RESULT}.

END PROCEDURE. /* maintainBatchQtyPer */

/*===========================================================================*/
PROCEDURE maintainFormulaQty:
/*---------------------------------------------------------------------------
      Purpose:  Reconcile quantity per unit, quantity per batch and
                percent of batch fields contingent upon value of ps_qty_type
   Exceptions:  NONE
        Notes:
      History:
---------------------------------------------------------------------------*/
   define input parameter componentUm as character no-undo.
   define parameter buffer pProductStructureBuffer for ps_mstr.

   define buffer bom_mstrBuffer for bom_mstr.
   define variable batch_size as decimal no-undo.
   define variable bom_um as character no-undo.
   define variable conv as decimal initial 1 no-undo.

   do on error undo, return error {&GENERAL-APP-EXCEPT}:

      for first bom_mstr fields (bom_batch bom_batch_um)
      no-lock where bom_parent = ps_par:
         assign bom_um = bom_batch_um
            batch_size = bom_batch.
      end.

      if batch_size = 0 then batch_size = 1.

      if ps_qty_type = "B" then do:
         ps_qty_per = ps_qty_per_b / batch_size.
      end.
      else if ps_qty_type = "P" then do:

         {pxrun.i &PROC = 'validatePercentofBatchUm'
                 &PARAM = "(input ps_qty_type,
                            input bom_um,
                            input ps_comp,
                            input componentUm,
                            output conv)"
         }
         if return-value <> {&SUCCESS-RESULT} then
            return error return-value.

         assign ps_qty_per_b = ps_batch_pct * .01 * batch_size / conv
                  ps_qty_per = ps_qty_per_b / batch_size.
      end.
      else if ps_qty_type = "" then do:
         assign ps_qty_per = ps_qty_per_b
              ps_batch_pct = 0.
      end.

   end. /* do on error undo, return {&GENERAL-APP-EXCEPT}: */

   return {&SUCCESS-RESULT}.

END PROCEDURE. /* maintainFormulaQty */

/*===========================================================================*/
PROCEDURE preEditFormulaValidation:
/*---------------------------------------------------------------------------
      Purpose:  Validate the formula ps_mstr record for attributes prior to edit
   Exceptions:  NONE
        Notes:
      History:
---------------------------------------------------------------------------*/
   define parameter buffer pProductStructureBuffer for ps_mstr.

   do on error undo, return error {&GENERAL-APP-EXCEPT}:

      {pxrun.i &PROC = 'validateNotAlternateStructure'
              &PARAM = "(input pProductStructureBuffer.ps_ps_code)"
      }
      if return-value <> {&SUCCESS-RESULT} then
         return error return-value.

      {pxrun.i &PROC = 'validateNotJointStructure'
              &PARAM = "(input pProductStructureBuffer.ps_ps_code)"
      }
      if return-value <> {&SUCCESS-RESULT} then
         return error return-value.

  end.
  return {&SUCCESS-RESULT}.
END PROCEDURE. /* preEditFormulaValidation */

/*===========================================================================*/
PROCEDURE preEditStructureValidation:
/*---------------------------------------------------------------------------
      Purpose:  Validate the ps_mstr record attributes prior to edit
   Exceptions:  NONE
        Notes:
      History:
---------------------------------------------------------------------------*/
   define parameter buffer pProductStructureBuffer for ps_mstr.

   do on error undo, return error {&GENERAL-APP-EXCEPT}:

      {pxrun.i &PROC = 'validateNotAlternateStructure'
              &PARAM = "(input pProductStructureBuffer.ps_ps_code)"
      }
      if return-value <> {&SUCCESS-RESULT} then
         return error return-value.

      {pxrun.i &PROC = 'validateNotJointStructure'
              &PARAM = "(input pProductStructureBuffer.ps_ps_code)"
      }
      if return-value <> {&SUCCESS-RESULT} then
         return error return-value.

      {pxrun.i &PROC = 'validateNotBatchStructure'
              &PARAM = "(input pProductStructureBuffer.ps_qty_type)"
      }
      if return-value <> {&SUCCESS-RESULT} then
         return error return-value.

      {pxrun.i &PROC = 'validateNotPercentBatch'
              &PARAM = "(input pProductStructureBuffer.ps_qty_type)"
      }
      if return-value <> {&SUCCESS-RESULT} then
         return error return-value.

  end.
  return {&SUCCESS-RESULT}.
END PROCEDURE. /* preEditStructureValidation */

/*===========================================================================*/
PROCEDURE processRead:
/*---------------------------------------------------------------------------
      Purpose:  Reads Product Structure Component record
                depending on the lock & wait flags
   Exceptions:  NONE
        Notes:
      History:
---------------------------------------------------------------------------*/
   define input parameter pParentItem as character no-undo.
   define input parameter pComponentItem as character no-undo.
   define input parameter pReferenceCode as character no-undo.
   define input parameter pStartEffective as date no-undo.

   define parameter buffer pProductStructureBuffer for ps_mstr.
   define input parameter pLockFlag as logical no-undo.
   define input parameter pWaitFlag as logical no-undo.

   do on error undo, return error {&GENERAL-APP-EXCEPT}:

      if plockflag then do:
         if PWaitFlag then do:
            find pProductStructureBuffer
            where ps_par = pParentItem
             and ps_comp = pComponentItem
              and ps_ref = pReferenceCode
            and ps_start = pStartEffective
            exclusive-lock no-error.
         end.
         else do:
            find pProductStructureBuffer
            where ps_par = pParentItem
             and ps_comp = pComponentItem
              and ps_ref = pReferenceCode
            and ps_start = pStartEffective
            exclusive-lock no-wait no-error.

            if locked pProductStructureBuffer
               then return {&RECORD-LOCKED}.
         end.

         if not available pProductStructureBuffer
            then return {&RECORD-NOT-FOUND}.

      end. /* if plockflag then do: */
      else do:

         for first pProductStructureBuffer no-lock
         where ps_par = pParentItem
          and ps_comp = pComponentItem
           and ps_ref = pReferenceCode
         and ps_start = pStartEffective:
            return {&SUCCESS-RESULT}.
         end.

         return {&RECORD-NOT-FOUND}.
      end.
   end. /* do on error undo, return error {&GENERAL-APP-EXCEPT}: */

   return {&SUCCESS-RESULT}.

END PROCEDURE. /* processRead */

/*===========================================================================*/
PROCEDURE setInitialFormulaValues:
/*---------------------------------------------------------------------------
      Purpose:  Sets formula related fields on new records
   Exceptions:  NONE
        Notes:
      History:
---------------------------------------------------------------------------*/
   define parameter buffer pProductStructureComponent for ps_mstr.

   do on error undo, return error {&GENERAL-APP-EXCEPT}:

      /* Give initial values as necessary */
      assign ps_qty_type = "B".

   end. /* do on error undo, return {&GENERAL-APP-EXCEPT}: */

   return {&SUCCESS-RESULT}.

END PROCEDURE. /* setInitialFormulaValues */

/*===========================================================================*/
PROCEDURE setModificationInfo:
/*---------------------------------------------------------------------------
      Purpose:  Stores audit entries into product structure buffer
   Exceptions:  NONE
        Notes:
      History:
---------------------------------------------------------------------------*/
   define parameter buffer pProductStructureComponent for ps_mstr.

   do on error undo, return error {&GENERAL-APP-EXCEPT}:

      /* Store modify date and userid */
      assign
         ps_mod_date = today
         ps_userid   = global_userid.
   end. /* do on error undo, return {&GENERAL-APP-EXCEPT}: */
   return {&SUCCESS-RESULT}.
END PROCEDURE. /* setModificationInfo */

/*===========================================================================*/
PROCEDURE updateMrpFlags:
/*---------------------------------------------------------------------------
      Purpose:  Update the MRP flags for affected items
   Exceptions:  NONE
        Notes:
      History:
---------------------------------------------------------------------------*/
   define input parameter pParentItem as character no-undo.
   define input parameter pUpdateLevels as logical no-undo.

   do on error undo, return error {&GENERAL-APP-EXCEPT}:

      /*! Update the mrp required flag for appropriate items
      *  (manufactured items which somehow reference this
      *  parent code as their bom code).
      *  Do not update low  level codes (second passed parameter) */
      {gprun.i ""bmpsmtc.p"" "(pParentItem,pUpdateLevels)" }

      /*! Locate phantom structure and 'bom code' parents of this
      *  parent code to apply the logic in bmpsmtc.p so that
      *  their mrp flags are properly updated. */
      {gprun.i ""bmpsmtd.p"" "(pParentItem)" }

   end. /* do on error undo, return {&GENERAL-APP-EXCEPT}: */
   return {&SUCCESS-RESULT}.

END PROCEDURE. /* updateMrpFlags */

/*===========================================================================*/
PROCEDURE validateBatchPercent:
/*---------------------------------------------------------------------------
     Purpose:  Validate that percent of batch does not exceed 100% for batch
               and percent of batch formula records.
  Exceptions:  NONE
       Notes:
     History:
---------------------------------------------------------------------------*/
   define input parameter pParent as character no-undo.
   define input parameter pStartDate as date no-undo.
   define input parameter pEndDate as date no-undo.
   define input parameter pQtyType as character no-undo.

   define buffer ps_mstrBuffer for ps_mstr.
   define variable batchPercent as decimal no-undo.
   define variable validationDate as date no-undo.
   define variable messageDetails as character no-undo.

   if pQtyType = "P" then
   do on error undo, return error {&GENERAL-APP-EXCEPT}:

      assign
         batchPercent = 0.

      if pStartDate <> ? then validationDate = pStartDate.
      else if pEndDate <> ? then validationDate = pEndDate.
      else validationDate = today.

      /* Add up batch percentage amounts */
      for each ps_mstrBuffer no-lock where
         ps_mstrBuffer.ps_par = pParent and
         (ps_mstrBuffer.ps_qty_type = "P" or
          ps_mstrBuffer.ps_qty_type = "B") and
         (ps_mstrBuffer.ps_start <= validationDate or
          ps_mstrBuffer.ps_start = ?) and
         (ps_mstrBuffer.ps_end >= validationDate or
          ps_mstrBuffer.ps_end = ?):

         batchPercent = batchPercent + ps_mstrBuffer.ps_batch_pct.
      end. /* for each ps_mstrBuffer no-lock where */

      if batchPercent <> 0
      then do:
         messageDetails =
            "(" + string(batchPercent) + "%) " + string(validationDate).

         if batchPercent > 100
         then do:
            {pxmsg.i &MSGNUM=4605
                     &ERRORLEVEL={&WARNING-RESULT}
                     &MSGARG1=messageDetails
                     &FIELDNAME=""ps_batch_pct""  }
         end.
         else do:
            {pxmsg.i &MSGNUM=4605
                     &ERRORLEVEL={&INFORMATION-RESULT}
                     &MSGARG1=messageDetails
                     &FIELDNAME=""ps_batch_pct"" }
         end.
     end. /* batchPercent <> 0 */

  end.
  return {&SUCCESS-RESULT}.
END PROCEDURE. /* validateBatchPercent */

/*===========================================================================*/
PROCEDURE validateBomExists:
/*---------------------------------------------------------------------------
     Purpose:  Validate that if item does not exist, the bom code does
  Exceptions:  NONE
       Notes:  &FIELDNAME on pxmsg.i removed since this validation is used
               for multiple physical fields.  The proper field name can be
               passed into the validation procedure using pxrun.i &FIELD-LIST
     History:
---------------------------------------------------------------------------*/

   define input parameter pItem as character no-undo.

   define buffer itemMasterBuffer for pt_mstr.
   define buffer bomMasterBuffer for bom_mstr.

   do on error undo, return error {&GENERAL-APP-EXCEPT}:

     /* Lookup item record */
     if not can-find (itemMasterBuffer where pt_part = pItem)
     then do:
        /* Check to see if BOM code already exists */
        if not can-find (bomMasterBuffer where bom_parent = pItem)
        then do:
           /* 231  - Item number or bom code must exist */
           {pxmsg.i &MSGNUM=231
                    &ERRORLEVEL={&APP-ERROR-RESULT}
           }
           return error {&APP-ERROR-RESULT}.
        end.
     end.
  end.
  return {&SUCCESS-RESULT}.
END PROCEDURE. /* validateBomExists */

/*============================================================================*/
PROCEDURE validateComponentId:
/*---------------------------------------------------------------------------
   Purpose:     To validate the entered component ID for blank value
   Exceptions:  NONE
   Notes:
   History:
---------------------------------------------------------------------------*/
   define input parameter pComponentId as character no-undo.

   do on error undo, return error {&GENERAL-APP-EXCEPT}:

      if pComponentId = "" then do:

         /* 40 - BLANK NOT ALLOWED. */
         {pxmsg.i &MSGNUM = 40
              &ERRORLEVEL = {&APP-ERROR-RESULT}
              &FIELDNAME=""ps_comp"" }
         return error {&APP-ERROR-RESULT}.

      end. /* if input pComponentId = "" then do: */

   end. /* do on error undo, return error {&GENERAL-APP-EXCEPT}: */
   return {&SUCCESS-RESULT}.

END PROCEDURE. /* validateComponentId */

/*===========================================================================*/
PROCEDURE validateCyclicStructures:
/*---------------------------------------------------------------------------
     Purpose:  Validate that structure does not introduce cyclic relationship
  Exceptions:  NONE
       Notes:
     History:
---------------------------------------------------------------------------*/

   define input parameter pRecno as recid no-undo.

   do on error undo, return error {&GENERAL-APP-EXCEPT}:

      /* Check for cyclic product structures */
      {gprun.i ""bmpscxfa.p"" "(input-output pRecno)"}
      if pRecno = 0
      then do:
         /* 206  - Cyclic product structure not allowed */
         {pxmsg.i &MSGNUM=206
                  &ERRORLEVEL={&APP-ERROR-RESULT}
                  &FIELDNAME=""ps_comp""
         }
         return error {&APP-ERROR-RESULT}.
      end.
   end.
   return {&SUCCESS-RESULT}.
END PROCEDURE. /* validateCyclicStructures */

/*===========================================================================*/
PROCEDURE validateEffectiveDates:
/*---------------------------------------------------------------------------
     Purpose:  Validate that structure does not overlap effective dates of
               other structures with same parent/component/reference values
  Exceptions:  NONE
       Notes:
     History:
---------------------------------------------------------------------------*/
   define parameter buffer pProductStructureBuffer for ps_mstr.
   define input parameter overlap-error-level as integer no-undo.

   define buffer ps_mstrBuffer for ps_mstr.
   define variable dateConflict as logical initial no no-undo.

   do on error undo, return error {&GENERAL-APP-EXCEPT}:

      if (pProductStructureBuffer.ps_start <> ?
      and pProductStructureBuffer.ps_end <> ?) then
      if pProductStructureBuffer.ps_start > pProductStructureBuffer.ps_end
      then do:
         /* 4 - Start date must be prior to end date */
         {pxmsg.i &MSGNUM=4
                  &ERRORLEVEL={&APP-ERROR-RESULT}
                  &FIELDNAME=""ps_start""
         }
         return error {&APP-ERROR-RESULT}.
      end. /* if ps_start > ps_end then do: */

      for each ps_mstrBuffer fields (ps_comp ps_end ps_par ps_ref ps_start)
      no-lock
      where ps_mstrBuffer.ps_par = pProductStructureBuffer.ps_par
      and  ps_mstrBuffer.ps_comp = pProductStructureBuffer.ps_comp
      and   ps_mstrBuffer.ps_ref = pProductStructureBuffer.ps_ref:

         if recid(ps_mstrBuffer) <> recid(pProductStructureBuffer)
         then do:

            if (ps_mstrBuffer.ps_start = ?
               and pProductStructureBuffer.ps_start = ?)
            or (ps_mstrBuffer.ps_end = ?
               and pProductStructureBuffer.ps_end = ?)
            or (ps_mstrBuffer.ps_start = ?
               and ps_mstrBuffer.ps_end = ?)
            or (pProductStructureBuffer.ps_start = ?
               and pProductStructureBuffer.ps_end = ?)
            then do:
               dateConflict = yes.
               leave.
            end.

            else if (pProductStructureBuffer.ps_start = ?)
            then do:
               if (ps_mstrBuffer.ps_start <= pProductStructureBuffer.ps_end)
               then do:
                  dateConflict = yes.
                  leave.
               end.
            end.

            else if (pProductStructureBuffer.ps_end = ?)
            then do:
               if (ps_mstrBuffer.ps_end >= pProductStructureBuffer.ps_start)
               then do:
                  dateConflict = yes.
                  leave.
               end.
            end.

            else do:
               if (ps_mstrBuffer.ps_start = ?)
               then do:
                  if (ps_mstrBuffer.ps_end >= pProductStructureBuffer.ps_start)
                  then do:
                     dateConflict = yes.
                     leave.
                  end.
               end.

               else if (ps_mstrBuffer.ps_end = ?)
               then do:
                  if (ps_mstrBuffer.ps_start <= pProductStructureBuffer.ps_end)
                  then do:
                     dateConflict = yes.
                     leave.
                  end.
               end.

               else
               if ((ps_mstrBuffer.ps_start <= pProductStructureBuffer.ps_end)
               and (ps_mstrBuffer.ps_end >= pProductStructureBuffer.ps_start))
               then do:
                  dateConflict = yes.
                  leave.
               end.
            end.
         end.
      end.

      if dateConflict then do:

         if overlap-error-level = 2 then do:
                /* 122  - Date ranges may not overlap */
                {pxmsg.i &MSGNUM=122 &ERRORLEVEL={&WARNING-RESULT}
                         &FIELDNAME=""ps_start""
                }
                return error {&WARNING-RESULT}.
           end.
           else do:
                /* 122  - Date ranges may not overlap */
                {pxmsg.i &MSGNUM=122 &ERRORLEVEL={&APP-ERROR-RESULT}
                         &FIELDNAME=""ps_start""
                }
                return error {&APP-ERROR-RESULT}.
           end.
      end.
   end.

   return {&SUCCESS-RESULT}.

END PROCEDURE. /* validateEffectiveDates */

/*===========================================================================*/
PROCEDURE validateItemNotBaseProcess:
/*---------------------------------------------------------------------------
     Purpose:  Validate that item has joint type not equal to 5 (base process)
  Exceptions:  NONE
       Notes:
     History:
---------------------------------------------------------------------------*/

   define input parameter pItem as character no-undo.

   define buffer itemMasterBuffer for pt_mstr.

   do on error undo, return error {&GENERAL-APP-EXCEPT}:

     /* Look up joint product type for item */
     for first itemMasterBuffer fields (pt_joint_type pt_part)
     no-lock where pt_part = pItem:

        /* See if component item is a base process */
        if pt_joint_type = "5"
        then do:
           /* 6521 - Component may not be a base process */
           {pxmsg.i &MSGNUM=6521 &ERRORLEVEL={&APP-ERROR-RESULT}
                    &FIELDNAME=""ps_comp""
           }
           return error {&APP-ERROR-RESULT}.
        end.
     end.
  end.
  return {&SUCCESS-RESULT}.
END PROCEDURE. /* validateItemNotBaseProcess */

/*===========================================================================*/
PROCEDURE validateItemStatus :
/*---------------------------------------------------------------------------
     Purpose:  Validate that item has status that permits transaction
  Exceptions:  NONE
       Notes:
     History:
---------------------------------------------------------------------------*/

   define input parameter pItem as character no-undo.
   define input parameter pTransactionCode as character no-undo.

   define variable statusValue as character no-undo.
   define buffer itemMasterBuffer for pt_mstr.
   define buffer itemStatusBuffer for isd_det.
   define buffer bomMasterBuffer for bom_mstr.

   do on error undo, return error {&GENERAL-APP-EXCEPT}:

     /* Lookup item status value for item */
     for first itemMasterBuffer no-lock where pt_part = pItem:
        statusValue = pt_status.
        substring (statusValue,9,1) = "#".

        /* See if requested transaction is restricted for item status */
        if can-find (itemStatusBuffer where isd_status = statusValue
        and isd_tr_type = pTransactionCode)
        then do:
           /* 358  - Restricted procedure for item status code */
           {pxmsg.i &MSGNUM=358 &ERRORLEVEL={&APP-ERROR-RESULT}
                    &FIELDNAME=""ps_comp""
           }
           return error {&APP-ERROR-RESULT}.
        end.
     end.
  end.
  return {&SUCCESS-RESULT}.
END PROCEDURE. /* validateItemStatus */

/*===========================================================================*/
PROCEDURE validateNotAlternateStructure:
/*---------------------------------------------------------------------------
      Purpose:  Validate the ps_mstr is not an alternate structure
                (ps_ps_code = "A")
   Exceptions:  Alternate structure maintenance (only) is allowed to
                create & maintain these structure records
        Notes:
      History:
---------------------------------------------------------------------------*/
   define input parameter pStructureType as character no-undo.

   do on error undo, return error {&GENERAL-APP-EXCEPT}:
      if pStructureType = "A"
      then do:
         /* 598  - Alternate structure not allowed */
         {pxmsg.i &MSGNUM=598 &ERRORLEVEL={&APP-ERROR-RESULT}
                  &FIELDNAME=""ps_comp""
         }
         return error {&APP-ERROR-RESULT}.
      end.
   end.
   return {&SUCCESS-RESULT}.
END PROCEDURE. /* validateNotAlternateStructure */

/*===========================================================================*/
PROCEDURE validateNotBatchStructure:
/*---------------------------------------------------------------------------
      Purpose:  Validate the ps_mstr is not a batch structure
                (ps_qty_type = "B")
   Exceptions:  Formula maintenance (only) is allowed to create &
                maintain these structure records
        Notes:
      History:
---------------------------------------------------------------------------*/
   define input parameter pQuantityType as character no-undo.

   do on error undo, return error {&GENERAL-APP-EXCEPT}:
      if pQuantityType = "B"
      then do:
         /* 4607 - Change not allowed to batch structure */
         {pxmsg.i &MSGNUM=4607 &ERRORLEVEL={&APP-ERROR-RESULT}
                  &FIELDNAME=""ps_comp""
         }
         return error {&APP-ERROR-RESULT}.
      end.
   end.
   return {&SUCCESS-RESULT}.
END PROCEDURE. /* validateNotBatchStructure */

/*===========================================================================*/
PROCEDURE validateNotJointStructure:
/*---------------------------------------------------------------------------
      Purpose:  Validate the ps_mstr is not a joint product structure
                (ps_ps_code = "J")
   Exceptions:  Joint product maintenance (only) is allowed to create &
                maintain these structure records
        Notes:
      History:
---------------------------------------------------------------------------*/
   define input parameter pStructureType as character no-undo.

   do on error undo, return error {&GENERAL-APP-EXCEPT}:
      if pStructureType = "J"
      then do:
         /* 6509  - May not update a joint product structure */
         {pxmsg.i &MSGNUM=6509 &ERRORLEVEL={&APP-ERROR-RESULT}
                  &FIELDNAME=""ps_comp""
         }
         return error {&APP-ERROR-RESULT}.
      end. /* if ps_ps_code = "J" then do: */
   end.
   return {&SUCCESS-RESULT}.
END PROCEDURE. /* validateNotJointStructure */

/*===========================================================================*/
PROCEDURE validateNotPercentBatch:
/*---------------------------------------------------------------------------
      Purpose:  Validate the ps_mstr is not a percent of batch structure
                (ps_qty_type = "P")
   Exceptions:  Formula maintenance (only) is allowed to create & maintain
                these structure records
        Notes:
      History:
---------------------------------------------------------------------------*/
   define input parameter pQuantityType as character no-undo.

   do on error undo, return error {&GENERAL-APP-EXCEPT}:
      if pQuantityType = "P"
      then do:
         /* 4604 - Percent of batch structure */
         {pxmsg.i &MSGNUM=4604 &ERRORLEVEL={&APP-ERROR-RESULT}}
         return error {&APP-ERROR-RESULT}.
      end.
   end.
   return {&SUCCESS-RESULT}.
END PROCEDURE. /* validateNotPercentBatch */

/*===========================================================================*/
PROCEDURE validatePercentofBatchUm:
/*---------------------------------------------------------------------------
      Purpose:  Validate that percent of batch formula records
                    have compatible (convertible) units of measure
   Exceptions:  None
        Notes:
      History:
---------------------------------------------------------------------------*/
   define input parameter pQuantityType as character no-undo.
   define input parameter pBomUM as character no-undo.
   define input parameter pComponent as character no-undo.
   define input parameter pComponentUM as character no-undo.
   define output parameter pConv as decimal no-undo.

   pConv = 1.

   do on error undo, return error {&GENERAL-APP-EXCEPT}:
      if pQuantityType = "P"
      then do:

         if pBomUM <> pComponentUM
         then do:
            {gprun.i ""gpumcnv.p""
                "(pComponentUM, pBomUM, pComponent, output pConv)"}
            if pConv = ?
            then do:
               /* 4600 - Component UM is different from parent UM */
               {pxmsg.i &MSGNUM=4600 &ERRORLEVEL={&APP-ERROR-RESULT}
                        &FIELDNAME=""ps_comp""
               }

               /* 33 - No unit of measure conversion exists */
               {pxmsg.i &MSGNUM=33 &ERRORLEVEL={&APP-ERROR-RESULT}
                        &FIELDNAME=""ps_comp""
               }

               return error {&APP-ERROR-RESULT}.

            end. /* if pConv = ? then do: */
         end. /* if pBomUM <> pComponentUM then do: */

      end. /* if pQuantityType = "P" then do: */
   end. /* do on error undo, return error */

   if pConv = 0 then pConv = 1.

   return {&SUCCESS-RESULT}.

END PROCEDURE. /* validatePercentofBatchUm */

/*===========================================================================*/
PROCEDURE validatePhantomComponentNotJointStructure:
/*---------------------------------------------------------------------------
      Purpose:  Validate that the component of a local phantom structure
                is not the parent of a joint product
   Exceptions:  None
        Notes:
      History:
---------------------------------------------------------------------------*/
   define input parameter pStructureType as character no-undo.
   define input parameter pComponent as character no-undo.

   define buffer ps_mstrBuffer for ps_mstr.

   do on error undo, return error {&GENERAL-APP-EXCEPT}:
      if pStructureType = "X"
      then do:

         for first ps_mstrBuffer fields (ps_comp ps_ps_code)
         no-lock where ps_mstrBuffer.ps_par = pComponent
         and ps_mstrBuffer.ps_ps_code = "J":
            /* 6534 - A joint product may not be a component
                      in a phantom structure */
            {pxmsg.i &MSGNUM=6534 &ERRORLEVEL={&APP-ERROR-RESULT}
                     &FIELDNAME=""ps_comp""
            }
            return error {&APP-ERROR-RESULT}.
         end.
      end.
   end.
   return {&SUCCESS-RESULT}.
END PROCEDURE. /* validatePhantomComponentNotJointStructure */

/*===========================================================================*/
PROCEDURE validateProductStructure:
/*---------------------------------------------------------------------------
      Purpose:  Validate the ps_mstr record attributes prior to commit
   Exceptions:  NONE
        Notes:
      History:
---------------------------------------------------------------------------*/
   define parameter buffer pProductStructureBuffer for ps_mstr.

   define variable errorlevel as integer initial 3 no-undo.

   do on error undo, return error {&GENERAL-APP-EXCEPT}:

      {pxrun.i &PROC = 'validateNotJointStructure'
              &PARAM = "(input pProductStructureBuffer.ps_ps_code)"
      }
      if return-value <> {&SUCCESS-RESULT} then
         return error return-value.

      {pxrun.i &PROC = 'validateQtyType'
              &PARAM = "(input pProductStructureBuffer.ps_qty_type)"
      }
      if return-value <> {&SUCCESS-RESULT} then
         return error return-value.

      {pxrun.i &PROC = 'validateBatchPercent'
              &PARAM = "(input pProductStructureBuffer.ps_par,
                         input pProductStructureBuffer.ps_start,
                         input pProductStructureBuffer.ps_end,
                         input pProductStructureBuffer.ps_qty_type)"
      }
      if return-value <> {&SUCCESS-RESULT} then
          return error return-value.

      {pxrun.i &PROC = 'validatePsPsCode'
              &PARAM = "(input pProductStructureBuffer.ps_ps_code)"
      }
      if return-value <> {&SUCCESS-RESULT} then
         return error return-value.

      {pxrun.i &PROC = 'validatePsScrpPct'
              &PARAM = "(input pProductStructureBuffer.ps_scrp_pct)"
      }

      {pxrun.i &PROC = 'validatePsFcstPct'
              &PARAM = "(input pProductStructureBuffer.ps_fcst_pct)"
      }

      {pxrun.i &PROC = 'validatePsGroup'
              &PARAM = "(input pProductStructureBuffer.ps_group)"
              &FIELD-LIST="ps_group"
      }

      {pxrun.i &PROC = 'validatePsProcess'
              &PARAM = "(input pProductStructureBuffer.ps_process)"
              &FIELD-LIST="ps_process"
      }

      {pxrun.i &PROC = 'validatePhantomComponentNotJointStructure'
              &PARAM = "(input pProductStructureBuffer.ps_ps_code,
                         input pProductStructureBuffer.ps_comp)"
      }
      if return-value <> {&SUCCESS-RESULT} then
         return error return-value.

      {pxrun.i &PROC = 'validateEffectiveDates'
              &PARAM = "(buffer pProductStructureBuffer,input errorlevel)"
      }
      if return-value <> {&SUCCESS-RESULT} then
         return error return-value.

      {pxrun.i &PROC = 'validateUniqueStructureSequence'
              &PARAM = "(buffer pProductStructureBuffer)"
              &CATCHERROR = true
      }
      if return-value <> {&SUCCESS-RESULT} then
         return error return-value.
  end.
  return {&SUCCESS-RESULT}.
END PROCEDURE. /* validateProductStructure */

/*===========================================================================*/
PROCEDURE validateUniqueStructureSequence:
/*---------------------------------------------------------------------------
      Purpose:  Validate the ps_item_no is not used for a different
                component in this structure
   Exceptions:  NONE
        Notes:  Warning message only, not an error
      History:
---------------------------------------------------------------------------*/
   define parameter buffer pProductStructureBuffer for ps_mstr.

   define buffer ps_mstrBuffer for ps_mstr.

   do on error undo, return error {&GENERAL-APP-EXCEPT}:

      if pProductStructureBuffer.ps_item_no <> 0
      then do:

         for first ps_mstrBuffer
         fields (ps_comp ps_item_no ps_par)
         no-lock
         where ps_mstrBuffer.ps_par = pProductStructureBuffer.ps_par
         and ps_mstrBuffer.ps_item_no = pProductStructureBuffer.ps_item_no
         and ps_mstrBuffer.ps_comp <> pProductStructureBuffer.ps_comp:

            /* ITEM DEFINED WITH A DIFFERENT ITEM/COMPONENT RELATIONSHIP */
            {pxmsg.i &MSGNUM=54 &ERRORLEVEL={&WARNING-RESULT}
                     &FIELDNAME=""ps_item_no""
            }

            return {&WARNING-RESULT}.

         end. /* FOR FIRST ps_mstrBuffer */

      end. /* IF pProductStructureBuffer.ps_item_no <> 0 */

   end. /* DO ON ERROR UNDO, RETURN ERROR {&GENERAL-APP-EXCEPT} */

   return {&SUCCESS-RESULT}.

END PROCEDURE. /* validateUniqueStructureSequence */

/*===========================================================================*/
PROCEDURE processWrite:
/*---------------------------------------------------------------------------
      Purpose:  Commit the ps_mstr record buffer and trigger any
                required post update processing
   Exceptions:  NONE
        Notes:
      History:
---------------------------------------------------------------------------*/
   define parameter buffer pProductStructureBuffer for ps_mstr.

   define variable updateLevels as logical initial no no-undo.
   define buffer ps_mstrBuffer for ps_mstr.

   do on error undo, return error {&GENERAL-APP-EXCEPT}:

      {pxrun.i &PROC = 'validateProductStructure'
              &PARAM = "(buffer pProductStructureBuffer)"
      }
      if return-value <> {&SUCCESS-RESULT} then
         return error return-value.

      {pxrun.i &PROC = 'setModificationInfo'
              &PARAM = "(buffer pProductStructureBuffer)"
      }
      if return-value <> {&SUCCESS-RESULT} then
         return error return-value.

      if new(pProductStructureBuffer)
      then
         updateLevels = yes.

      {pxrun.i &PROC = 'updateMrpFlags'
              &PARAM = "(input pProductStructureBuffer.ps_par,updateLevels)"
      }
      if return-value <> {&SUCCESS-RESULT} then
         return error return-value.

   end. /* DO ON ERROR UNDO, RETURN ERROR */

   return {&SUCCESS-RESULT}.
END PROCEDURE. /* processWrite */


/* ========================================================================== */
/* ****************  SCHEMA GENERATED VALIDATION PROCEDURES ***************** */
/*============================================================================*/

/*============================================================================*/
PROCEDURE validatePsPar :
/*------------------------------------------------------------------------------
Purpose:       Validate ps_mstr.ps_par
Exceptions:    NONE
Conditions:
        Pre:   ps_mstr(r)
        Post:  None.
Notes:         Pulled from schema.
History:
------------------------------------------------------------------------------*/
   define input parameter pValue as character no-undo.

   do on error undo, return error {&GENERAL-APP-EXCEPT}:
      /* ERROR: ITEM NUMBER OR BOM CODE MUST EXIST. PLEASE RE-ENTER. */
      /* MSG-MSTR POSSIBILITIES */
      /* 231 - Item number or BOM code must exist */
      if not({psval.v pValue}) then do:
         {pxmsg.i
            &MSGNUM=231
            &ERRORLEVEL={&APP-ERROR-RESULT}
            &FIELDNAME=""ps_par""
         }
         return error {&APP-ERROR-RESULT}.
      end.
   end.
   return {&SUCCESS-RESULT}.
END PROCEDURE. /* validatePsPar */

/*============================================================================*/
PROCEDURE validatePsComp :
/*------------------------------------------------------------------------------
Purpose:       Validate ps_mstr.ps_comp
Exceptions:    NONE
Conditions:
        Pre:   ps_mstr(r)
        Post:  None.
Notes:         Pulled from schema.
History:
------------------------------------------------------------------------------*/
   define input parameter pValue as character no-undo.

   do on error undo, return error {&GENERAL-APP-EXCEPT}:
      /* ERROR: ITEM NUMBER OR BOM CODE MUST EXIST. PLEASE RE-ENTER. */
      /* MSG-MSTR POSSIBILITIES */
      /* 231 - Item number or BOM code must exist */
      if not({psval.v pValue}) then do:
         {pxmsg.i
            &MSGNUM=231
            &ERRORLEVEL={&APP-ERROR-RESULT}
            &FIELDNAME=""ps_comp""
         }
         return error {&APP-ERROR-RESULT}.
      end.
   end.
   return {&SUCCESS-RESULT}.
END PROCEDURE. /* validatePsComp */

/*============================================================================*/
PROCEDURE validatePsFcstPct:
/*------------------------------------------------------------------------------
Purpose:       Validate ps_mstr.ps_fcst_pct
Exceptions:    NONE
Conditions:
        Pre:   ps_mstr(r)
        Post:  None.
Notes:         Pulled from schema.
History:
------------------------------------------------------------------------------*/
   define input parameter pValue as character no-undo.

   do on error undo, return error {&GENERAL-APP-EXCEPT}:
      /* ERROR: PERCENTAGE CANNOT EXCEED 100. PLEASE RE-ENTER. */
      if not(decimal(pValue) >= 0 and decimal(pValue) <= 100) then do:
         {pxmsg.i
            &MSGNUM=3536
            &ERRORLEVEL={&APP-ERROR-RESULT}
            &FIELDNAME=""ps_fcst_pct""
         }
         return error {&APP-ERROR-RESULT}.
      end.
   end.
   return {&SUCCESS-RESULT}.
END PROCEDURE. /* validatePsFcstPct */

/*============================================================================*/
PROCEDURE validatePsGroup:
/*------------------------------------------------------------------------------
Purpose:       Validate ps_mstr.ps_group
Exceptions:    NONE
Conditions:
        Pre:   ps_mstr(r)
        Post:  None.
Notes:         Pulled from schema.
History:
------------------------------------------------------------------------------*/
   define input parameter pValue as character no-undo.

   do on error undo, return error return-value:
      {pxrun.i
         &PROC='validateGeneralizedCodes'
         &PROGRAM='gpcodxr.p'
         &HANDLE=ph_gpcodxr
         &PARAM="(input 'ps_group',
            input '',
            input pValue,
            input '')"
         &NOERROR}
   end.
   return {&SUCCESS-RESULT}.
END PROCEDURE. /* validatePsGroup */

/*============================================================================*/
PROCEDURE validatePsProcess:
/*------------------------------------------------------------------------------
Purpose:       Validate ps_mstr.ps_process
Exceptions:    NONE
Conditions:
        Pre:   ps_mstr(r)
        Post:  None.
Notes:         Pulled from schema.
History:
------------------------------------------------------------------------------*/
   define input parameter pValue as character no-undo.

   do on error undo, return error return-value:
      {pxrun.i
         &PROC='validateGeneralizedCodes'
         &PROGRAM='gpcodxr.p'
         &HANDLE=ph_gpcodxr
         &PARAM="(input 'ps_process',
            input '',
            input pValue,
            input '')"
         &NOERROR}
   end.
   return {&SUCCESS-RESULT}.
END PROCEDURE. /* validatePsProcess */

/*============================================================================*/
PROCEDURE validatePsPsCode :
/*------------------------------------------------------------------------------
Purpose:       Validate ps_mstr.ps_ps_code
Exceptions:    NONE
Conditions:
        Pre:   ps_mstr(r)
        Post:  None.
Notes:         Pulled from schema and then modified to be
               Product Structure Maintenance specific
History:
------------------------------------------------------------------------------*/
   define input parameter pValue as character no-undo.

   do on error undo, return error {&GENERAL-APP-EXCEPT}:
      if not(lookup(pValue,"P,O,D,X") > 0  or pValue = "") then do:
         /* 4087 - Must be P, O, D, X or blank. */
         {pxmsg.i &MSGNUM=4087 &ERRORLEVEL={&APP-ERROR-RESULT}
                  &FIELDNAME=""ps_ps_code""
         }
         return error {&APP-ERROR-RESULT}.
      end.
   end.
   return {&SUCCESS-RESULT}.
END PROCEDURE. /* validatePsPsCode */

/*============================================================================*/
PROCEDURE validatePsScrpPct:
/*------------------------------------------------------------------------------
Purpose:       Validate ps_mstr.ps_scrp_pct
Exceptions:    NONE
Conditions:
        Pre:   ps_mstr(r)
        Post:  None.
Notes:         Pulled from schema.
History:
------------------------------------------------------------------------------*/
   define input parameter pValue as character no-undo.

   do on error undo, return error {&GENERAL-APP-EXCEPT}:
      /* ERROR: PERCENTAGE MUST BE LESS THAN 100. PLEASE RE-ENTER. */
      if not(decimal(pValue) >=0 and decimal(pValue) < 100) then do:
         {pxmsg.i
            &MSGNUM=3499
            &ERRORLEVEL={&APP-ERROR-RESULT}
            &FIELDNAME=""ps_scrp_pct""
         }
         return error {&APP-ERROR-RESULT}.
      end.
   end.
   return {&SUCCESS-RESULT}.
END PROCEDURE. /* validatePsScrpPct */

/*============================================================================*/
PROCEDURE validateQtyType :
/*------------------------------------------------------------------------------
Purpose:       Validate ps_mstr.ps_qty_type
Exceptions:    NONE
Conditions:
        Pre:   ps_mstr(r)
        Post:  None.
Notes:         Pulled from formula maintenance update statement
History:
------------------------------------------------------------------------------*/
   define input parameter pValue as character no-undo.

   do on error undo, return error {&GENERAL-APP-EXCEPT}:
      if not(lookup(pValue,"B,P") > 0  or pValue = "") then do:
         /* 6910 - Invalid quantity type. */
         {pxmsg.i &MSGNUM=6910 &ERRORLEVEL={&APP-ERROR-RESULT}
                  &FIELDNAME=""ps_qty_type""
         }
         return error {&APP-ERROR-RESULT}.
      end.
   end.
   return {&SUCCESS-RESULT}.
END PROCEDURE. /* validateQtyType */
